#include "cvectorbase.h"

/**
 * init - initialization
 * @param size
 */
template <typename T>
void CVectorBase<T>::init(TIndex size) {
  setSize(size);
  createItems();
  clearToZero();
}
//---------------------------------------------------------------------------

/**
 * operator+= - adds given vector to this vector
 * @param v
 * @return this
 */
template <typename T>
CVectorBase<T>& CVectorBase<T>::operator += (const CVectorBase<T> &v) {
  for (TIndex i = 0; i < getSize(); i++) this->items[i] += v.getItemsPtr()[i];
  return *this;
}
//---------------------------------------------------------------------------

/**
 * operator-= - subtracts given vector from this vector
 * @param v
 * @return this
 */
template <typename T>
CVectorBase<T>& CVectorBase<T>::operator -= (const CVectorBase<T> &v) {
  for (TIndex i = 0; i < getSize(); i++) this->items[i] -= v.getItemsPtr()[i];
  return *this;
}
//---------------------------------------------------------------------------

/**
 * operator*= - multiplies this vector by given vector
 * @param num
 * @return this
 */
template <typename T>
CVectorBase<T>& CVectorBase<T>::operator *= (T num) {
  for (TIndex i = 0; i < getSize(); i++) this->items[i] *= num;
  return *this;
}
//---------------------------------------------------------------------------

/**
 * operator/= - divides this vector by given vector
 * @param num
 * @return this
 */
template <typename T>
CVectorBase<T>& CVectorBase<T>::operator /= (T num) {
  for (TIndex i = 0; i < getSize(); i++) this->items[i] /= num;
  return *this;
}
//---------------------------------------------------------------------------

/**
 * operator== - compares two vectors by their items
 * @param v
 * @return true if vectors are equal
 */
template <typename T>
bool CVectorBase<T>::operator == (const CVectorBase<T> &v) const {

  // If sizes of vectors do not match, they are not equal
  if (getSize() != v.getSize()) return false;

  // Compare items
  for (TIndex i = 0; i < getSize(); i++) {
    if (this->items[i] != v.getItemsPtr()[i]) return false;
  }
  return true;
}
//---------------------------------------------------------------------------

/**
 * operator!= - compares two vectors by their items
 * @param v
 * @return true if vectors are not equal
 */
template <typename T>
bool CVectorBase<T>::operator != (const CVectorBase<T> &v) const {
  return !(*this == v);
}
//---------------------------------------------------------------------------

/**
 * operator> - compares items of two vectors
 * @param v
 * @return true if first vector is greater than second one
 */
template <typename T>
bool CVectorBase<T>::operator > (const CVectorBase<T> &v) const {

  // If sizes of vectors do not match, they are not comparable
  if (getSize() != v.getSize()) return false;

  // First vector is greater than second, if each of its items is greater
  // than items of the second vector, if one or more items are not
  // greater, the first vector is not greater as well
  for (TIndex i = 0; i < getSize(); i++) {
    if (this->items[i] <= v.getItemsPtr()[i]) return false;
  }
  return true;
}
//---------------------------------------------------------------------------

/**
 * operator< - compares items of two vectors
 * @param v
 * @return true if this vectors is lesser than give one
 */
template <typename T>
bool CVectorBase<T>::operator < (const CVectorBase<T> &v) const {

  // If sizes of vectors do not match, they are not comparable
  if (getSize() != v.getSize()) return false;

  // First vector is lesser than second, if each of its items is lesser
  // than items of the second vector, if one or more items are greater,
  // the first vector is not lesser as well
  for (TIndex i = 0; i < getSize(); i++) {
    if (this->items[i] >= v.getItemsPtr()[i]) return false;
  }
  return true;
}
//---------------------------------------------------------------------------

/**
 * operator>= - compares items of two vectors
 * @param v
 * @return true if first vector is greater or equal as second one
 */
template <typename T>
bool CVectorBase<T>::operator >= (const CVectorBase<T> &v) const {

  // If sizes of vectors do not match, they are not comparable
  if (getSize() != v.getSize()) return false;

  // Compare vectors
  for (TIndex i = 0; i < getSize(); i++) {
    if (this->items[i] < v.getItemsPtr()[i]) return false;
  }
  return true;
}
//---------------------------------------------------------------------------

/**
 * operator<= - compares items of two vectors
 * @param v
 * @return true if first vector is lesser or equal as second one
 */
template <typename T>
bool CVectorBase<T>::operator <= (const CVectorBase<T> &v) const {

  // If sizes of vectors do not match, they are not comparable
  if (getSize() != v.getSize()) return false;

  // Compare vectors
  for (TIndex i = 0; i < getSize(); i++) {
    if (this->items[i] > v.getItemsPtr()[i]) return false;
  }
  return true;
}
//---------------------------------------------------------------------------

/**
 * get - returns vector item on given position
 * @param index
 * @return vector item on index position
 */
template <typename T>
T CVectorBase<T>::get(TIndex index) const {

  // Check size
  if (index >= getSize()) {
    throw CIndexOutOfBoundsException(getClassName(), "get");
  }
  return items[index];
}
//---------------------------------------------------------------------------

/**
 * set - sets vector item on given position
 * @param index
 * @param value
 */
template <typename T>
void CVectorBase<T>::set(TIndex index, T value) {

  // Check size
  if (index >= getSize()) {
    throw CIndexOutOfBoundsException(getClassName(), "set");
  }
  items[index] = value;
}
//---------------------------------------------------------------------------

/**
 * swap - swaps two vector items
 * @param index1
 * @param index2
 */
template <typename T>
void CVectorBase<T>::swap(TIndex index1, TIndex index2) {

  // Check size
  if (index1 >= getSize() || index2 >= getSize()) {
    throw CIndexOutOfBoundsException(getClassName(), "swap");
  }
  T tmp(items[index1]);
  items[index1] = items[index2];
  items[index2] = tmp;
}
//---------------------------------------------------------------------------

/**
 * getItemsPtr - returns pointer on vector items
 * @return pointer on vector items
 */
template <typename T>
T* CVectorBase<T>::getItemsPtr() const {
  return items;
}
//---------------------------------------------------------------------------

/**
 * clearToZero - sets all items of vector to zero
 */
template <typename T>
void CVectorBase<T>::clearToZero() {
  fill_n(items, getSize(), T(0));
}
//---------------------------------------------------------------------------

/**
 * createItems - creates vector items
 */
template <typename T>
void CVectorBase<T>::createItems() {
  this->items = new T[getSize()];
}
//---------------------------------------------------------------------------

/**
 * getNorm - returns norm (size) of vector
 * @return vector norm
 */
template <typename T>
T CVectorBase<T>::getNorm() const {
  return CMath<T>::sqrt(dot((*this), (*this)));
}
//---------------------------------------------------------------------------

/**
 * normalize - normalizes vector
 */
template <typename T>
void CVectorBase<T>::normalize() {
  *this *= T(1) / getNorm();
}
//---------------------------------------------------------------------------

/**
 * toString - prints vector information to string
 * @return retezec
 */
template <typename T>
string CVectorBase<T>::toString() const {

  // Out stream
  ostringstream stream;

  // Print items to stream
  for (TIndex i = 0; i < getSize(); i++) stream << items[i] << " ";
  stream << endl;

  return stream.str();
}
//---------------------------------------------------------------------------

/**
 * copyFrom - copy data from given vector
 * @param v
 */
template <typename T>
void CVectorBase<T>::copyFrom(const CVectorBase &v) {
  setSize(v.getSize());
  items = new T[getSize()];
  memcpy(items, v.getItemsPtr(), getSize() * sizeof(T));
}
//---------------------------------------------------------------------------

/**
 * free - erase vector items
 */
template <typename T>
void CVectorBase<T>::free() {

  // Delete items of vector
  if (items != NULL) {
    delete [] items;
    items = NULL;
  }

  // Null
  setSize(0);
}
//---------------------------------------------------------------------------

/**
 * dot - dot product of two vectors
 * @param v1
 * @param v2
 * @return dot product
 */
template <typename T>
T CVectorBase<T>::dot(const CVectorBase<T> &v1, const CVectorBase<T> &v2) {
  T result(0);
  for (TIndex i = 0; i < v1.getSize(); i++) {
    result += v1.getItemsPtr()[i] * v2.getItemsPtr()[i];
  }
  return result;
}
//---------------------------------------------------------------------------

template class CVectorBase<char>;
template class CVectorBase<unsigned char>;
template class CVectorBase<short>;
template class CVectorBase<unsigned short>;
template class CVectorBase<int>;
template class CVectorBase<unsigned int>;
template class CVectorBase<long>;
template class CVectorBase<unsigned long>;
template class CVectorBase<float>;
template class CVectorBase<double>;
template class CVectorBase<CBigInt>;
template class CVectorBase<CFraction>;
